package com.symaster.common.geom.entity;

import com.symaster.common.geom.util.IDUtil;
import com.symaster.common.geom.util.PointUtil;

import java.io.Serializable;
import java.util.List;

/**
 * @author yinmiao
 * @date 2022-01-17 10:34
 */
public class Node implements Serializable, Cloneable {

    private static final long serialVersionUID = -49587623409534L;

    private final int version;
    private Integer id;
    private String uuid;
    private Polygon polygon;
    private Polygon swellPolygon;
    private double marge;
    private Double angle;
    private List<Node> nodes;
    private String attachedInformation;

    /**
     * 返回支持的最小版本
     */
    public static int minVersion() {
        return 1;
    }

    private Node() {
        this.id = IDUtil.getId();
        this.version = 1;
    }

    public Node(Polygon polygon, double marge) {
        this.version = 1;
        this.polygon = polygon;
        this.marge = marge;
        swellPolygon = swellTransform(polygon, marge);
        if (swellPolygon.isEmpty()) {
            throw new IllegalArgumentException("无法创建该图形");
        }
    }

    public void setMarge(double marge) {
        this.marge = marge;
    }

    public Integer getVersion() {
        return version;
    }

    public double getMarge() {
        return marge;
    }

    public List<Node> getNodes() {
        return nodes;
    }

    public void setNodes(List<Node> nodes) {
        for (Node node : nodes) {
            if (node == this) {
                throw new IllegalArgumentException("不能添加自身作为子节点");
            }
        }

        this.nodes = nodes;
    }

    public double getX() {
        return polygon.getX();
    }

    public double getY() {
        return polygon.getY();
    }

    public double getWidth() {
        return polygon.getWidth();
    }

    public double getHeight() {
        return polygon.getHeight();
    }

    public void move(double x, double y) {
        Vector translateVector = PointUtil.getTranslateVector(polygon.getX(), polygon.getY(), x, y);
        translate(translateVector);
    }

    public void move(Point point) {
        Vector translateVector = PointUtil.getTranslateVector(polygon.getX(), polygon.getY(), point.x, point.y);
        translate(translateVector);
    }

    public void rotateTransform(double angle) {
        rotateTransform(angle, polygon.getCenter());
    }

    public void rotateTransform(double angle, Point center) {
        polygon.rotateTransform(center, angle);
        swellPolygon = swellTransform(polygon, marge);
        if (nodes != null && !nodes.isEmpty()) {
            for (Node node : nodes) {
                node.rotateTransform(angle, new Point(0, 0));
            }
        }
    }

    public void translate(Vector vector) {
        translate(vector.getX(), vector.getY());
    }

    public void updateSwellPolygon() {
        swellPolygon = swellTransform(polygon, marge);
    }

    public void scaleTransform(double scale) {
        polygon.scaleTransform(new Point(polygon.getX(), polygon.getY()), scale);
        if (swellPolygon != null) {
            swellPolygon = swellTransform(polygon, marge);
        }
    }

    public void translate(double xn, double yn) {
        polygon.translate(xn, yn);
        if (swellPolygon != null) {
            swellPolygon.translate(xn, yn);
        }
    }

    public boolean collide(Node node) {
        return this.polygon.collide(node.getPolygon());
    }

    private static Polygon swellTransform(Polygon polygon, double marge) {
        if (polygon == null || polygon.getYpoints() == null || polygon.getXpoints() == null || polygon.getXpoints().length != polygon.getYpoints().length) {
            throw new IllegalArgumentException("等距缩放异常 - polygon == null || polygon.getYpoints() == null || polygon.getXpoints() == null || polygon.getXpoints().length != polygon.getYpoints().length");
        }

        if (Math.abs(marge) <= 0.00000001D) {
            return polygon.clone();
        }

        return polygon.offsetOfCopy(marge);
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUuid() {
        return uuid;
    }

    public void setUuid(String uuid) {
        this.uuid = uuid;
    }

    public Polygon getPolygon() {
        return polygon;
    }

    public void setPolygon(Polygon polygon) {
        this.polygon = polygon;
    }

    public Polygon getSwellPolygon() {
        return swellPolygon;
    }

    public void setSwellPolygon(Polygon swellPolygon) {
        this.swellPolygon = swellPolygon;
    }

    public Double getAngle() {
        return angle;
    }

    public void setAngle(Double angle) {
        this.angle = angle;
    }

    public String getAttachedInformation() {
        return attachedInformation;
    }

    public void setAttachedInformation(String attachedInformation) {
        this.attachedInformation = attachedInformation;
    }

    @Override
    public String toString() {
        return "Node{" +
                "id=" + id +
                ", uuid='" + uuid + '\'' +
                ", polygon=" + polygon +
                ", swellPolygon=" + swellPolygon +
                ", angle=" + angle +
                ", attachedInformation='" + attachedInformation + '\'' +
                '}';
    }

    @Override
    public Node clone() {
        try {
            Node clone = (Node) super.clone();
            clone.angle = this.angle;
            clone.id = this.id;
            clone.uuid = this.uuid;
            clone.polygon = this.polygon.clone();
            clone.swellPolygon = this.swellPolygon.clone();
            clone.marge = this.marge;
            clone.angle = this.angle;
            clone.nodes = this.nodes;
            clone.attachedInformation = this.attachedInformation;
            return clone;
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(String.format("克隆对象异常 %s", e.getMessage()));
        }
    }
}
